package cn.bon.common.interceptor;

import cn.bon.common.exception.DbException;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.builder.StaticSqlSource;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.scripting.defaults.RawSqlSource;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * @Author Lc_cL
 * @Date 2023/12/25
 * @Description 实现插入数据的时候自动更新 insertTime 和 updateTime
 */
@Slf4j
@Intercepts({
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class MybatisTimeInterceptor implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        log.info("MybatisTimeInterceptor run...");

        Object[] args = invocation.getArgs();
        MappedStatement mappedStatement = (MappedStatement) args[0];

        // 获取SQL的命令类型
        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();

        // 获取参数对象
        Object parameter = args[1];

        BoundSql boundSql = mappedStatement.getBoundSql(parameter);
        String originSql = boundSql.getSql();

        if (sqlCommandType == SqlCommandType.INSERT) {
            // 插入操作时处理createTime和updateTime
            handleInsert(parameter);
        } else if (sqlCommandType == SqlCommandType.UPDATE) {
            // 更新操作时处理updateTime
            handleUpdate(parameter);
        }


        // 继续执行原方法
        return invocation.proceed();
    }


    /**
     * 处理插入操作
     *
     * @param parameter
     */
    private void handleInsert(Object parameter) {
        if (parameter != null) {
            try {
                // 获取字段对象
                Field creatTime = parameter.getClass().getDeclaredField("createTime");
                Field updateTime = parameter.getClass().getDeclaredField("updateTime");

                // 设置字段可访问
                creatTime.setAccessible(true);
                updateTime.setAccessible(true);

                // 设置字段值
                creatTime.set(parameter, LocalDateTime.now());
                updateTime.set(parameter, LocalDateTime.now());

                // 恢复字段访问权限
                creatTime.setAccessible(false);
                updateTime.setAccessible(false);

            } catch (NoSuchFieldException | IllegalAccessException e) {
                log.warn("该插入未包含时间字段");
            }
        }
    }

    /**
     * 处理更新操作
     *
     * @param parameter
     */
    private void handleUpdate(Object parameter) {
        if (parameter != null) {
            try {
                // 获取字段对象
                Field updateTime = parameter.getClass().getDeclaredField("updateTime");

                // 设置字段可访问
                updateTime.setAccessible(true);

                // 设置字段值
                updateTime.set(parameter, LocalDateTime.now());

                // 恢复字段访问权限
                updateTime.setAccessible(false);

            } catch (NoSuchFieldException | IllegalAccessException e) {
                log.warn("该条更新未设置更新时间字段");
            }

        }
    }
    /**
     * 逻辑删除
     *
     * @param parameter
     * @param is_deleted
     */

    /*private void handleDelFlag(Object parameter, boolean is_deleted) {
        if (parameter != null) {
            try {
                // 获取字段对象
                Field delFlag = parameter.getClass().getDeclaredField("delFlag");

                // 设置字段可访问
                delFlag.setAccessible(true);

                // 设置字段值
                if (is_deleted) {   //删除
                    delFlag.set(parameter, null);
                } else {    //未删除
                    delFlag.set(parameter, 1);
                }

                // 恢复字段访问权限
                delFlag.setAccessible(false);

            } catch (NoSuchFieldException | IllegalAccessException e) {
                log.warn("缺乏逻辑删除字段");
            }
        }
    }*/


    /**
     * 插入操作插入insertTime和updateTime
     *
     * @param mappedStatement
     * @param originSql
     */
/*    private void handleInsert(MappedStatement mappedStatement, String originSql) {
        //修改originSql
//        if (originSql.contains(""))  TODO

        modifyMappedStatement(mappedStatement, originSql);
    }

    private void handleUpdate(MappedStatement mappedStatement, String originSql) {
        //修改originSql
        if (originSql.contains("update_time")) return;

        // 获取当前时间
        LocalDateTime localDateTime = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");// 定义日期时间格式
        String formattedDateTime = localDateTime.format(formatter);// 格式化LocalDateTime为字符串

        if (originSql.contains("SET") || originSql.contains("set")) {     //TODO 修改时间序列化
            originSql = originSql.replace("SET", "SET update_time=" + formattedDateTime + " AND ");
            originSql = originSql.replace("set", "set update_time=" + formattedDateTime + " AND ");
        }

        modifyMappedStatement(mappedStatement, originSql);
    }*/

    /**
     * 反射 修改MappedStatement
     *
     * @param mappedStatement
     * @param sql
     */
/*    private void modifyMappedStatement(MappedStatement mappedStatement, String sql) {
        try {
            //暴力反射，修改sql
            Field rawSqlSourceField = mappedStatement.getClass().getDeclaredField("sqlSource");
            rawSqlSourceField.setAccessible(true);
            SqlSource rawSqlSource = (RawSqlSource) rawSqlSourceField.get(mappedStatement);


            Field staticSqlSourceFiled = rawSqlSource.getClass().getDeclaredField("sqlSource");
            staticSqlSourceFiled.setAccessible(true);
            SqlSource staticSqlSource = (StaticSqlSource) staticSqlSourceFiled.get(rawSqlSource);


            Field sqlField = staticSqlSource.getClass().getDeclaredField("sql");
            sqlField.setAccessible(true);

            sqlField.set(staticSqlSource, sql);
            staticSqlSourceFiled.set(rawSqlSource, staticSqlSource);
            rawSqlSourceField.set(mappedStatement, rawSqlSource);

            sqlField.setAccessible(false);
            staticSqlSourceFiled.setAccessible(false);
            rawSqlSourceField.setAccessible(false);

        } catch (NoSuchFieldException | IllegalAccessException e) {
            throw new DbException("更新 反射注入更新时间失败");
        }
    }*/
}
